﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using S7.Net;
using SqlSugar;
using SqlSugar.IOC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using CKS.PLC.Core;
using ZR.Model.Models.ProductionControl;

namespace CKS.PLC.Core
{
    /// <summary>
    /// 订阅动作基类
    /// 可根据不同项目自行定义ActionId
    /// </summary>
    public abstract class ActionBase
    {
       public DecodeValue Value { get; set; }
        public ActionBase(DecodeValue _value) { 
            this.Value = _value;
        }

        public IServiceProvider serviceProvider;
        public ILogger<ActionBase> logger;
        public ISqlSugarClient db;
        internal void InitConfig(IServiceProvider _serviceProvider)
        {
            
            serviceProvider = _serviceProvider;
            logger = serviceProvider.GetService<ILogger<ActionBase>>();
            db = DbScoped.SugarScope.GetConnection(0);
        }
        /// <summary>
        /// 执行订阅事件
        /// </summary>
        public abstract void Execute();

        /// <summary>
        /// 信号复位，对该操作回复信号重置
        /// </summary>
        public void SignalReset()
        {
            //var points = Value.LinkPositions.FindAll(a=>a.DataKind == 2);
            //foreach (var p in points) {
            //    Value.plcSession.Write(S7.Net.DataType.DataBlock, p.BlockDb, p.BytePosition, Convert.ToInt16(0)); //
            //}
           
        }

        internal static ActionBase GetInstance(DecodeValue value)
        {
            /// 如果多个站 每个站的每个DB文件的操作编号可以相同。
            /// 根据工站编号 - DB块 - 操作编号类
            /// 程序目录示例： OP50/DB3011/CKS01Action.cs、OP60/DB3010/CKS01Action.cs
            //  流程action 1 - 100 
            //              1 请求加工 2请求保存    
            //  纯数据 101 - 200

            /*
             插件式：每次执行前检查DLL是否发生变化，
                1.有变化则更新缓存程序集
                2.从缓存程序集提取实例执行
                
             
             */
            var position = value.Position;
            switch (position.PlcId)
            {
                case 1:
                    return GetOP10ActionInstance(value);
                case 8:
                    return GetOP80ActionInstance(value);
                    
                default:
                    throw new InvalidOperationException("当前工位编号逻辑尚未添加");
            }



            //switch (value.Position.ActionId)
            //{
            //    case 9999:
            //        return new Test00Action(value);
            //    case 1:
            //        return new Cks01Action(value);
            //    default:
            //        throw new InvalidOperationException("未实现的操作编号");
            //}
        }

        private static ActionBase GetOP10ActionInstance(DecodeValue value)
        {
            var position = value.Position;
            switch (position.ActionId)
            {
                case 1: //入口错误
                case 2: //使用次数达到报警
                    return new OP10.Cks01Action(value);
                case 10:
                    return new OP10.Cks10Action(value);
                case 20:
                    return new OP10.Cks20Action(value);
                case 30:
                    return new OP10.Cks30Action(value);
                default:
                    throw new InvalidOperationException("未实现的操作编号");
            }
        }

        private static ActionBase GetOP80ActionInstance(DecodeValue value)
        {
            var position = value.Position;
            switch (position.ActionId)
            {
                case 1:
                    return new OP80.DB3011.Work01Action(value);
                default:
                    throw new InvalidOperationException("未实现的操作编号");
            }
        }
        




        /// <summary>
        /// 读取单个点位的字符串数据
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public string ReadString(CksPlcDataPosition point)
        {
            var buffer = Value.plcSession.ReadBytes(DataType.DataBlock, point.BlockDb, (int)point.BytePosition, point.ByteLenth);
           return DataConversion.GetStringDataByBytes(buffer, 0, buffer.Length);
        }

        public string ReadCacheString(CksPlcDataPosition point)
        {
            // Value.
            return Value.AllValues.Find(a => a.Position.Id == point.Id).Value.ToString();
            //var buffer = Value.plcSession.ReadBytes(DataType.DataBlock, point.BlockDb, point.BytePosition, point.ByteLenth);
            //return DataConversion.GetStringDataByBytes(buffer, 0, buffer.Length);
        }


        public int ReadInt16(CksPlcDataPosition point)
        {
           return (int)Value.plcSession.Read(S7.Net.DataType.DataBlock, point.BlockDb, (int)point.BytePosition ,VarType.Int,1); //
        }

        /// <summary>
        /// 向指定点位写入 int16--对应plc的int值
        /// </summary>
        /// <param name="point"></param>
        /// <param name="value"></param>
        public void WriteInt16(CksPlcDataPosition point,Int16 value)
        {
            Value.plcSession.Write(S7.Net.DataType.DataBlock, point.BlockDb, (int)point.BytePosition, Convert.ToInt16(value)); //
        }

        public void WriteString(CksPlcDataPosition point,string value)
        {
            // 编码为字节数组
            byte[] stringBytes = Encoding.ASCII.GetBytes(value);
            // 构建带控制信息的字节数组
            byte[] dataString = new byte[stringBytes.Length + 2]; // 加2是为了存储控制信息
                                                                  // 添加控制信息
            dataString[0] = (byte)(point.ByteLenth - 2); //第一个字节是字符串的字节总数
            dataString[1] = (byte)(stringBytes.Length); // 第二个字节表示实际使用字节数量
                                                        // 复制字符串数据到字节数组
            Array.Copy(stringBytes, 0, dataString, 2, stringBytes.Length);
            // 将字节数组写入PLC
            Value.plcSession.WriteBytes(S7.Net.DataType.DataBlock, point.BlockDb, (int)point.BytePosition, dataString);
        }

        
    }
}
